﻿// 由于 STB_IMAGE_IMPLEMENTATION 将 std_image 被编译为 .cpp
// 文件，因此不放在头文件中
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

#include "MainOpenGLWidget.h"
#include "kernel/debug_timer.h"

using namespace CAGD;

#define CONVERT_TO_QVEC_3(vec)                                                                                         \
    QVector3D                                                                                                          \
    {                                                                                                                  \
        vec.X(), vec.Y(), vec.Z()                                                                                      \
    }

MainOpenGLWidget::MainOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent), m_shader(nullptr)
{
    // 开启鼠标追踪，启动强焦点，确保能获取按键信息
    setMouseTracking(true);
    setFocusPolicy(Qt::StrongFocus);

    // 创建交互类型，这里绑定着色器会有一些问题，但是无所谓
    AIS_Context::ShareContext(this);
}

MainOpenGLWidget::~MainOpenGLWidget()
{
    // 判断 OpenGL 资源是否成功初始化
    if (!isValid())
        return;

    // 首先移除 Context，防止 Context 中存放的数组对象在 GL 析构以后再次析构
    AIS_Context::ShareContext().DeleteContext();

    // 销毁对象，注意删除过程中迭代器的位置
    for (auto it : m_VAOs)
        glDeleteVertexArrays(1, &it.second);
    for (auto it : m_VBOs)
        glDeleteBuffers(1, &it.second);
    for (auto it : m_EBOs)
        glDeleteBuffers(1, &it.second);
    for (auto it : m_Inss)
        glDeleteBuffers(1, &it.second);
    for (auto it : m_UBOs)
        glDeleteBuffers(1, &it.second);

    for (auto it : m_textures)
        glDeleteTextures(1, &it.second);
    for (auto it : m_frames)
    {
        glDeleteFramebuffers(1, &it.second.frameID);
        glDeleteRenderbuffers(1, &it.second.RBO);
        glDeleteTextures(1, &it.second.textureID);
    }

    // 销毁字符纹理
    destroy_text_textures(this);

    // 移除着色器和场景
    for (auto it : m_shaders)
        delete it.second;
}

void MainOpenGLWidget::initializeGL()
{
    // 初始化 OpenGL 函数
    initializeOpenGLFunctions();

    // 生成默认纹理构造
    GenerateTexture(TEXTURE::DASH);
    BindTexture1D(TEXTURE::DASH);
    LoadTexture1D(TEXTURE::DASH);

    GenerateTexture(TEXTURE::SNIPPLE);
    BindTexture1D(TEXTURE::SNIPPLE);
    LoadTexture1D(TEXTURE::SNIPPLE, 1.0);

    // 2D 纹理
    GenerateTexture(TEXTURE::YELLOW2D);
    BindTexture2D(TEXTURE::YELLOW2D);
    LoadTexture2D(TEXTURE::YELLOW2D);

    GenerateTexture(TEXTURE::RED2D);
    BindTexture2D(TEXTURE::RED2D);
    LoadTexture2D(TEXTURE::RED2D);

    GenerateTexture(TEXTURE::GREEN2D);
    BindTexture2D(TEXTURE::GREEN2D);
    LoadTexture2D(TEXTURE::GREEN2D);

    GenerateTexture(TEXTURE::BLUE2D);
    BindTexture2D(TEXTURE::BLUE2D);
    LoadTexture2D(TEXTURE::BLUE2D);

    GenerateTexture(TEXTURE::WHITE2D);
    BindTexture2D(TEXTURE::WHITE2D);
    LoadTexture2D(TEXTURE::WHITE2D);

    GenerateTexture(TEXTURE::BLACK2D);
    BindTexture2D(TEXTURE::BLACK2D);
    LoadTexture2D(TEXTURE::BLACK2D);

    GenerateTexture(TEXTURE::CHESS);
    BindTexture2D(TEXTURE::CHESS);
    LoadTexture2D(TEXTURE::CHESS);

    // 初始化交互容器
    auto &context = AIS_Context::ShareContext();
    context.InitContext();

    // 创建字符纹理
    init_text_textures(this, 16);
}

void MainOpenGLWidget::paintGL()
{
    // 获取原始尺寸
    static int sw = width() * CAGD_SCALE_RATIO;
    static int sh = height() * CAGD_SCALE_RATIO;

    // 这里非常奇怪，当窗口尺寸改变的时候，仍然要按照原始尺寸设置窗口，会按照比例缩放视口
    glViewport(0, 0, sw, sh);

    // 启用混合、深度测试、模板测试
    glEnable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);

    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    TIMER_START(PaintEvent)

    // 绘制物体
    AIS_Context::ShareContext().PaintEvent();

    TIMER_QT_END(PaintEvent)
}

void MainOpenGLWidget::wheelEvent(QWheelEvent *event)
{
    TIMER_START(wheelEvent)

    // 调用滚轮消息
    AIS_Context::ShareContext().MouseWheelEvent({event->angleDelta().x(), event->angleDelta().y()});

    TIMER_QT_END(wheelEvent)

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::mousePressEvent(QMouseEvent *event)
{
    TIMER_START(mousePressEvent)

    // 获得按键
    Button button;
    if (event->button() == Qt::LeftButton)
        button = Button::LEFT;
    else if (event->button() == Qt::RightButton)
        button = Button::RIGHT;
    else
        button = Button::MIDDLE;

    // 调用按键消息
    AIS_Context::ShareContext().MousePressEvent({event->pos().x(), event->pos().y()}, button);

    TIMER_QT_END(mousePressEvent)

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::mouseReleaseEvent(QMouseEvent *event)
{
    TIMER_START(mouseReleaseEvent)

    // 调用按键消息
    AIS_Context::ShareContext().MouseReleaseEvent({event->pos().x(), event->pos().y()});

    TIMER_QT_END(mouseReleaseEvent)

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    TIMER_START(mouseMoveEvent)

    // 调用按键消息
    AIS_Context::ShareContext().MouseMoveEvent({event->pos().x(), event->pos().y()});

    TIMER_QT_END(mouseMoveEvent)

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    TIMER_START(keyPressEvent)

    // 映射键位
    Key key;
    switch (event->key())
    {
    case Qt::Key_Space:
        key = Key::SPACE;
        break;
    case Qt::Key_Escape:
        key = Key::ESC;
        break;
    case Qt::Key_Shift:
        key = Key::SHIFT;
        break;
    case Qt::Key_A:
        key = Key::A;
        break;
    case Qt::Key_B:
        key = Key::B;
        break;
    case Qt::Key_C:
        key = Key::C;
        break;
    case Qt::Key_D:
        key = Key::D;
        break;
    case Qt::Key_E:
        key = Key::E;
        break;
    case Qt::Key_F:
        key = Key::F;
        break;
    case Qt::Key_S:
        key = Key::S;
        break;
    case Qt::Key_V:
        key = Key::V;
        break;
    case Qt::Key_X:
        key = Key::X;
        break;
    case Qt::Key_Z:
        key = Key::Z;
        break;
    case Qt::Key_0:
        key = Key::K0;
        break;
    default:
        key = Key::NONE;
        break;
    }

    // 调用按键消息
    AIS_Context::ShareContext().KeyPressEvent(key);

    TIMER_QT_END(keyPressEvent)

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::keyReleaseEvent(QKeyEvent *event)
{
    // 映射键位
    Key key;
    switch (event->key())
    {
    case Qt::Key_Space:
        key = Key::SPACE;
        break;
    case Qt::Key_Escape:
        key = Key::ESC;
        break;
    case Qt::Key_Shift:
        key = Key::SHIFT;
        break;
    case Qt::Key_A:
        key = Key::A;
        break;
    case Qt::Key_B:
        key = Key::B;
        break;
    case Qt::Key_C:
        key = Key::C;
        break;
    case Qt::Key_D:
        key = Key::D;
        break;
    case Qt::Key_E:
        key = Key::E;
        break;
    case Qt::Key_F:
        key = Key::F;
        break;
    case Qt::Key_S:
        key = Key::S;
        break;
    case Qt::Key_V:
        key = Key::V;
        break;
    case Qt::Key_X:
        key = Key::X;
        break;
    case Qt::Key_Z:
        key = Key::Z;
        break;
    case Qt::Key_0:
        key = Key::K0;
        break;
    default:
        key = Key::NONE;
        break;
    }

    // 调用按键消息
    AIS_Context::ShareContext().KeyReleaseEvent(key);

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::resizeEvent(QResizeEvent *event)
{
    // 调用 resize
    AIS_Context::ShareContext().ResizeEvent(width(), height());

    // 同时刷新
    update();
    parentWidget()->update();
}

void MainOpenGLWidget::GenerateShader(int i, const char *vertexPath, const char *fragmentPath, const char *geometryPath)
{
    // 检查是否已经创建
    if (m_shaders.count(i) > 0)
        return;

    m_shaders[i] = new QOpenGLShaderProgram;

    // 链接着色器
    bool success;
    m_shaders[i]->addShaderFromSourceFile(QOpenGLShader::Vertex, vertexPath);
    m_shaders[i]->addShaderFromSourceFile(QOpenGLShader::Fragment, fragmentPath);

    // 如果载入几何着色器
    if (geometryPath != nullptr)
        m_shaders[i]->addShaderFromSourceFile(QOpenGLShader::Geometry, geometryPath);

    // 链接到程序
    success = m_shaders[i]->link();
    if (!success)
        qDebug() << "ERR:" << m_shaders[i]->log();
}

void MainOpenGLWidget::BindShader(int i)
{
    if (m_shaders.count(i) == 0)
    {
        qDebug() << "Program don't exist.";
        return;
    }

    m_shader = m_shaders[i];
    m_shader->bind();
}

void MainOpenGLWidget::DeleteShader(int i)
{
    if (m_shaders.count(i) == 0)
    {
        qDebug() << "Program don't exist.";
        return;
    }

    glDeleteShader(i);
    m_shaders.erase(i);
}

void MainOpenGLWidget::GenerateArray(int i)
{
    unsigned int VAO, VBO, EBO, Ins;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glGenBuffers(1, &Ins);

    m_VAOs[i] = VAO;
    m_VBOs[i] = VBO;
    m_EBOs[i] = EBO;
    m_Inss[i] = Ins;
}

void MainOpenGLWidget::BindArray(int i)
{
    if (m_VAOs.count(i) == 0)
    {
        qDebug() << "Array don't exist.";
        return;
    }

    glBindVertexArray(m_VAOs[i]);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[i]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBOs[i]);
}

void MainOpenGLWidget::BindInsArray(int i)
{
    if (m_Inss.count(i) == 0)
    {
        qDebug() << "Instance don't exist.";
        return;
    }

    glBindBuffer(GL_ARRAY_BUFFER, m_Inss[i]);
}

void MainOpenGLWidget::UnbindArray()
{
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void MainOpenGLWidget::DeleteArray(int i)
{
    if (m_VAOs.count(i) == 0)
    {
        qDebug() << "Array don't exist.";
        return;
    }

    glDeleteVertexArrays(1, &m_VAOs[i]);
    glDeleteBuffers(1, &m_VBOs[i]);
    glDeleteBuffers(1, &m_EBOs[i]);
    glDeleteBuffers(1, &m_Inss[i]);

    m_VAOs.erase(i);
    m_VBOs.erase(i);
    m_EBOs.erase(i);
    m_Inss.erase(i);
}

void MainOpenGLWidget::GenerateUBO(int i)
{
    unsigned int UBO;

    // 生成后直接绑定到 i 号位
    glGenBuffers(1, &UBO);
    glBindBufferBase(GL_UNIFORM_BUFFER, i, UBO);

    m_UBOs[i] = UBO;
}

void MainOpenGLWidget::BindUBO(int i)
{
    if (m_UBOs.count(i) == 0)
    {
        qDebug() << "UBO don't exist.";
        return;
    }

    glBindBuffer(GL_UNIFORM_BUFFER, m_UBOs[i]);
}

void MainOpenGLWidget::UnbindUBO()
{
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}

void MainOpenGLWidget::DeleteUBO(int i)
{
    if (m_UBOs.count(i) == 0)
    {
        qDebug() << "UBO don't exist.";
        return;
    }

    glDeleteBuffers(1, &m_UBOs[i]);
    m_UBOs.erase(i);
}

void MainOpenGLWidget::GenerateTexture(int i)
{
    unsigned int texture;
    glGenTextures(1, &texture);
    m_textures[i] = texture;
}

void MainOpenGLWidget::LoadTexture1D(TEXTURE texture, float a)
{
    float rgba[] = {1, 1, 1, a};

    // 生成纹理
    float texArray[16][4];
    for (int i = 0; i < 16; i++)
    {
        if (i % 2 == 0)
        {
            if (texture == TEXTURE::DASH)
            {
                texArray[i][0] = 0;
                texArray[i][1] = 0;
                texArray[i][2] = 0;
                texArray[i][3] = 1;
            }
            if (texture == TEXTURE::SNIPPLE)
            {
                texArray[i][0] = 0;
                texArray[i][1] = 0;
                texArray[i][2] = 0;
                texArray[i][3] = 0;
            }
        }
        else
        {
            texArray[i][0] = rgba[0];
            texArray[i][1] = rgba[1];
            texArray[i][2] = rgba[2];
            texArray[i][3] = rgba[3];
        }
    }

    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 16, 0, GL_RGBA, GL_FLOAT, texArray);
    glGenerateMipmap(GL_TEXTURE_1D);

    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

void MainOpenGLWidget::LoadTexture2D(const char *file)
{
    // 加载图片前翻转图片
    stbi_set_flip_vertically_on_load(true);

    // glTexImage2D 生成纹理，然后 glGenerateMipmap 产生多级渐远纹理
    int width, height, nrComponents;
    unsigned char *data = stbi_load(file, &width, &height, &nrComponents, 0);
    if (data)
    {
        // 判定图像数据类型
        GLenum format = GL_RGB;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        stbi_image_free(data);
    }
    else
    {
        qDebug() << "Texture failed to load at path: " << file;
        stbi_image_free(data);
    }
}

void MainOpenGLWidget::LoadTexture2D(TEXTURE texture, float a)
{
    float rgba[] = {0, 0, 0, a};

    switch (texture)
    {
    case TEXTURE::YELLOW2D:
        rgba[0] = rgba[1] = 1;
        break;
    case TEXTURE::RED2D:
        rgba[0] = 1;
        break;
    case TEXTURE::GREEN2D:
        rgba[1] = 1;
        break;
    case TEXTURE::BLUE2D:
        rgba[2] = 1;
        break;
    case TEXTURE::WHITE2D:
        rgba[0] = rgba[1] = rgba[2] = 1;
        break;
    case TEXTURE::BLACK2D:
    case TEXTURE::CHESS:
        break;
    default:
        qDebug() << "Texture don't exists.";
        break;
    }

    // 生成纹理
    float texArray[16][16][4];
    for (int i = 0; i < 16; i++)
    {
        for (int j = 0; j < 16; j++)
        {
            if (texture == TEXTURE::CHESS && (i + j) % 2 == 0)
            {
                texArray[i][j][0] = 1;
                texArray[i][j][1] = 1;
                texArray[i][j][2] = 1;
                texArray[i][j][3] = 1;
            }
            else
            {
                texArray[i][j][0] = rgba[0];
                texArray[i][j][1] = rgba[1];
                texArray[i][j][2] = rgba[2];
                texArray[i][j][3] = rgba[3];
            }
        }
    }

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_FLOAT, texArray);
    glGenerateMipmap(GL_TEXTURE_2D);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

void MainOpenGLWidget::LoadTextureCube(std::vector<const char *> files)
{
    // 取消纹理翻转
    stbi_set_flip_vertically_on_load(false);

    // glTexImage2D 生成纹理，然后 glGenerateMipmap 产生多级渐远纹理
    int width, height, nrComponents;
    for (unsigned int i = 0; i < files.size(); i++)
    {
        unsigned char *data = stbi_load(files[i], &width, &height, &nrComponents, 0);

        if (data)
        {
            // 判定图像数据类型
            GLenum format = GL_RGB;
            if (nrComponents == 1)
                format = GL_RED;
            else if (nrComponents == 3)
                format = GL_RGB;
            else if (nrComponents == 4)
                format = GL_RGBA;

            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE,
                         data);
            glGenerateMipmap(GL_TEXTURE_CUBE_MAP);

            stbi_image_free(data);
        }
        else
        {
            qDebug() << "Texture failed to load at path: " << files[i];
            stbi_image_free(data);
        }
    }

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

void MainOpenGLWidget::ActiveTexture(int i)
{
    glActiveTexture(GL_TEXTURE0 + i);
}

void MainOpenGLWidget::BindTexture1D(int i)
{
    if (m_textures.count(i) == 0)
    {
        qDebug() << "Texture don't exist.";
        return;
    }

    glBindTexture(GL_TEXTURE_1D, m_textures[i]);
}

void MainOpenGLWidget::BindTexture2D(int i)
{
    if (m_textures.count(i) == 0)
    {
        qDebug() << "Texture don't exist.";
        return;
    }

    glBindTexture(GL_TEXTURE_2D, m_textures[i]);
}

void MainOpenGLWidget::BindTextureCube(int i)
{
    if (m_textures.count(i) == 0)
    {
        qDebug() << "Texture don't exist.";
        return;
    }

    glBindTexture(GL_TEXTURE_CUBE_MAP, m_textures[i]);
}

void MainOpenGLWidget::UnbindTexture()
{
    glBindTexture(GL_TEXTURE_1D, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

void MainOpenGLWidget::DeleteTexture(int i)
{
    if (m_textures.count(i) == 0)
    {
        qDebug() << "Texture don't exist.";
        return;
    }

    glDeleteTextures(1, &m_textures[i]);
    m_textures.erase(i);
}

void MainOpenGLWidget::GenerateFrame(int i, int w, int h)
{
    if (m_frames.count(i) > 0)
    {
        qDebug() << "Frame exists.";
        return;
    }

    FrameData frameID;
    glGenFramebuffers(1, &frameID.frameID);
    glGenTextures(1, &frameID.textureID);
    glGenRenderbuffers(1, &frameID.RBO);
    m_frames[i] = frameID;

    glBindFramebuffer(GL_FRAMEBUFFER, frameID.frameID);

    // 创建纹理附件
    glBindTexture(GL_TEXTURE_2D, frameID.textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    // 创建渲染缓冲对象
    glBindRenderbuffer(GL_RENDERBUFFER, frameID.RBO);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    // 绑定到当前帧缓冲
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameID.textureID, 0);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, frameID.RBO);

    // 检查帧缓冲是否完整
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        qDebug() << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!";

    // 解除绑定
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
}

void MainOpenGLWidget::BindFrame(int i)
{
    if (m_frames.count(i) == 0)
    {
        qDebug() << "Frame don't exist.";
        return;
    }

    glBindFramebuffer(GL_FRAMEBUFFER, m_frames[i].frameID);
}

void MainOpenGLWidget::UnbindFrame()
{
    // 注意 Qt 中解绑需要将其绑定到默认的帧缓冲中，而不是 0
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
}

void MainOpenGLWidget::DeleteFrame(int i)
{
    if (m_frames.count(i) == 0)
    {
        qDebug() << "Frame don't exist.";
        return;
    }

    glDeleteFramebuffers(1, &m_frames[i].frameID);
    glDeleteRenderbuffers(1, &m_frames[i].RBO);
    glDeleteTextures(1, &m_frames[i].textureID);

    m_frames.erase(i);
}

QOpenGLShaderProgram *MainOpenGLWidget::GetShader()
{
    return m_shader;
}
